//
// Created by twetec on 25-8-16.
//

#include "../include/network_prober/backup_test/handle_ssh_backup_test.h"

#include <boost/json.hpp>
#include <libssh2.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <boost/algorithm/string/regex.hpp>
#include <boost/algorithm/string/join.hpp>


namespace network_prober::backup_test
{
// 过滤备份登录信息
static boost::regex s_backupResultLoginLineFilterRegxPattern{R"##(Last login:(.+)through ssh\.)##", boost::regex::icase};
// 备份信息More匹配
static boost::regex s_backupResultMoreSearchRegxPattern{R"##(([-]+)(\s*)More(\s*)[-]+)##", boost::regex::icase};

// static int g_waitsocket(int socket_fd, LIBSSH2_SESSION *session)
// {
//     struct timeval timeout;
//     int rc;
//     fd_set fd;
//     fd_set *writefd = NULL;
//     fd_set *readfd = NULL;
//     int dir;
//
//     timeout.tv_sec = 5;
//     timeout.tv_usec = 0;
//
//     FD_ZERO(&fd);
//     FD_SET(socket_fd, &fd);
//
//     /* now make sure we wait in the correct direction */
//     dir = libssh2_session_block_directions(session);
//
//
//     if (dir & LIBSSH2_SESSION_BLOCK_INBOUND)
//         readfd = &fd;
//
//     if (dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
//         writefd = &fd;
//
//     rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
//
//     return rc;
// }

static int s_waitSocket(int socket_fd, LIBSSH2_SESSION *session)
{
    int epoll_fd, rc{0};
    struct epoll_event ev, events;
    int timeout_ms = 5000; // 5秒超时
    int dir = libssh2_session_block_directions(session);

    // 创建epoll实例
    epoll_fd = epoll_create1(0);
    if (epoll_fd == -1) {
        return -1;
    }

    // 设置要监听的事件
    ev.events = 0;
    ev.data.fd = socket_fd;

    // 读事件
    if (dir & LIBSSH2_SESSION_BLOCK_INBOUND) {
        ev.events |= EPOLLIN;
    }
    // 写事件
    if (dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) {
        ev.events |= EPOLLOUT;
    }

    // 添加socket到epoll监听
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1) {
        close(epoll_fd);
        return -1;
    }

    // 等待事件
    rc = epoll_wait(epoll_fd, &events, 1, timeout_ms);

    // 关闭epoll实例
    close(epoll_fd);

    return rc;
}

// libssh2初始化程序，只执行一次
static std::once_flag g_libssh2InitOnceFlag;

void tag_invoke(boost::json::value_from_tag, boost::json::value &jv, SSHBackupTestResultIPv4 const &c)
{
    auto& ja = jv.emplace_object();

    ja["interface"] = c.interface;
    ja["target"] = c.target;
    ja["port"] = c.port;
    ja["backupData"] = c.backupData;
}

HandleSSHBackupTestIPv4::HandleSSHBackupTestIPv4(SSHBackupTestParamsIPv4&& testParams)
: m_interface(testParams.interface), m_target(testParams.target), m_port(testParams.port), m_username(testParams.username),
m_password(testParams.password), m_privilegedPassword(testParams.privilegedPassword), m_command(testParams.command)
{
    // 初始化libssh2库，在应用程序启动时，只调用一次
    std::call_once(g_libssh2InitOnceFlag, [] {
        // 初始化正常
        if (libssh2_init(0)) {
            SPDLOG_ERROR("libssh2库加载失败...");
            throw std::runtime_error("libssh2库加载失败...");
        }
    });
}

void HandleSSHBackupTestIPv4::setOnTestedCallback(std::function<void(SSHBackupTestResultIPv4 &&)> callback)
{
    m_onTestedCallback = std::move(callback);
}

void HandleSSHBackupTestIPv4::test()
{
    // 指向当前对象的shared_ptr
    auto self{shared_from_this()};

    // 执行备份任务
    m_onTestedCallbackFuture = std::async(std::launch::async, [this, self]() {
        // 备份结果对象
        SSHBackupTestResultIPv4 testResult {
            .interface = m_interface,
            .target = m_target,
            .port = m_port,
            .backupData = ""
        };

        // 请求备份内容，如果请求失败，则重试。最大重试3次
        for (std::size_t i = 0; i < 3; ++i) {
            // libssh执行结果
            int rc{0};

            // 创建socket(套接字) [AF_INET: IPv4, SOCK_STREAM: TCP]
            int socketfd = socket(AF_INET, SOCK_STREAM, 0);
            if (socketfd < 0) {
                // 输出日志
                SPDLOG_INFO("sockfd创建失败: {}", strerror(errno));
                // 结束执行
                continue;
            }

            // 设定本地网卡地址
            struct sockaddr_in interfaceAddr;
            memset(&interfaceAddr, 0, sizeof(interfaceAddr));
            interfaceAddr.sin_family = AF_INET;
            interfaceAddr.sin_port = htons(0);
            if (inet_pton(AF_INET, m_interface.c_str(), &interfaceAddr.sin_addr) <= 0) {
                // 关闭socket
                close(socketfd);
                // 输出日志
                SPDLOG_INFO("sockfd: {} - 网口地址设置失败: {}", socketfd, strerror(errno));
                // 停止执行
                continue;
            }

            // 绑定本机网口
            if (bind(socketfd, (sockaddr *)&interfaceAddr, sizeof(interfaceAddr)) < 0) {
                // 关闭socket
                close(socketfd);
                // 输出日志
                SPDLOG_INFO("sockfd: {} - 网口地址绑定失败: {}", socketfd, strerror(errno));
                // 停止执行
                continue;
            }

            // 设置目标地址
            struct sockaddr_in targetAddr;
            memset(&targetAddr, 0, sizeof(targetAddr));
            targetAddr.sin_family = AF_INET;
            targetAddr.sin_port = htons(m_port);
            if (inet_pton(AF_INET, m_target.c_str(), &targetAddr.sin_addr) <= 0) {
                // 关闭socket
                close(socketfd);
                // 输出日志
                SPDLOG_INFO("sockfd: {} - 目标地址设置失败: {}", socketfd, strerror(errno));
                // 停止执行
                continue;
            }

            // 连接目标地址
            if (connect(socketfd, (struct sockaddr *)&targetAddr, sizeof(targetAddr)) < 0) {
                // 关闭socket
                close(socketfd);
                // 输出日志
                SPDLOG_INFO("服务器连接失败: {}", strerror(errno));
                // 停止执行
                continue;
            }

            // 创建SSH会话
            LIBSSH2_SESSION* session = libssh2_session_init();
            if (!session) {
                // 关闭socket
                LIBSSH2_SOCKET_CLOSE(socketfd);
                // 输出日志
                SPDLOG_INFO("sockfd: {} - SSH会话创建失败: {}", socketfd, strerror(errno));
                // 结束执行
                continue;
            }

            // 设置会话为非阻塞模式
            libssh2_session_set_blocking(session, 0);

            // SSH会话握手，握手没有结果时等待
            while ((rc = libssh2_session_handshake(session, socketfd)) == LIBSSH2_ERROR_EAGAIN) {
                s_waitSocket(socketfd, session);
            }

            // 握手有结果时，如果握手失败
            if (rc != 0) {
                // 释放session
                libssh2_session_free(session);
                // 关闭socket
                LIBSSH2_SOCKET_CLOSE(socketfd);
                // 输出日志
                SPDLOG_INFO("sockfd: {} - 握手失败: {}", socketfd, strerror(errno));
                // 结束执行
                continue;
            }

            // 握手成功后，进行帐号认证.未出结果时等待
            while ((rc = libssh2_userauth_password(session, m_username.c_str(), m_password.c_str())) == LIBSSH2_ERROR_EAGAIN) {
                s_waitSocket(socketfd, session);
            }

            // 认证出结果后，如果认证失败
            if (rc != 0) {
                // 释放session
                libssh2_session_free(session);
                // 关闭socket
                LIBSSH2_SOCKET_CLOSE(socketfd);
                // 输出日志
                SPDLOG_INFO("sockfd: {} - 帐号密码认证失败: {} || usn: {} & pwd: {}", socketfd, strerror(errno), m_username.c_str(), m_password.c_str());
                // 结束执行
                continue;
            }

            // 打开通道
            LIBSSH2_CHANNEL* channel = nullptr;
            // 如果通道打开中，则等待
            while ((channel = libssh2_channel_open_session(session)) == NULL && libssh2_session_last_error(session, NULL, NULL, 0) == LIBSSH2_ERROR_EAGAIN) {
                s_waitSocket(socketfd, session);
            }
            // 通道打开出结果后，如果通道打开失败
            if(!channel) {
                // 释放session
                libssh2_session_free(session);
                // 关闭socket
                LIBSSH2_SOCKET_CLOSE(socketfd);
                // 输出日志
                SPDLOG_INFO("sockfd: {} - 通道打开失败: {}", socketfd, strerror(errno));
                // 结束执行
                continue;
            }

            // 请求虚拟终端，未出结果时等待
            while ((rc = libssh2_channel_request_pty(channel, "xterm")) == LIBSSH2_ERROR_EAGAIN) {
                s_waitSocket(socketfd, session);
            }
            // 出结果后，如果请求失败
            if (rc != 0) {
                // 关闭channel
                libssh2_channel_close(channel);
                // 释放channel
                libssh2_channel_free(channel);
                // 释放session
                libssh2_session_free(session);
                // 关闭socket
                LIBSSH2_SOCKET_CLOSE(socketfd);
                // 输出日志
                SPDLOG_INFO("sockfd: {} - 虚拟终端请求失败: {}", socketfd, strerror(errno));
                // 结束执行
                continue;
            }

            // 请求互动shell
            while ((rc = libssh2_channel_shell(channel)) == LIBSSH2_ERROR_EAGAIN) {
                s_waitSocket(socketfd, session);
            }
            if (rc != 0) {
                // 关闭channel
                libssh2_channel_close(channel);
                // 释放channel
                libssh2_channel_free(channel);
                // 释放session
                libssh2_session_free(session);
                // 关闭socket
                LIBSSH2_SOCKET_CLOSE(socketfd);
                // 输出日志
                SPDLOG_INFO("sockfd: {} - 互动shell创建失败: {}", socketfd, strerror(errno));
                // 结束执行
                continue;
            }

            // // 执行命令 命令末尾追加换行，让其可执行
            // std::string command = m_command;

            while ((rc = libssh2_channel_write(channel, m_command.c_str(), strlen(m_command.c_str()))) == LIBSSH2_ERROR_EAGAIN) {
                s_waitSocket(socketfd, session);
            }
            // 如果执行命令失败
            if (rc <= 0) {
                // 关闭channel
                libssh2_channel_close(channel);
                // 释放channel
                libssh2_channel_free(channel);
                // 释放session
                libssh2_session_free(session);
                // 关闭socket
                LIBSSH2_SOCKET_CLOSE(socketfd);
                // 输出日志
                SPDLOG_INFO("sockfd: {} - 备份命令执行失败: {}", socketfd, strerror(errno));
                // 结束执行
                continue;
            }

            // 读取命令执行的结果
            constexpr std::size_t BACKUP_DATA_SIZE = 50 * 1024;  // 备份数据区尺寸
            char backupData[BACKUP_DATA_SIZE];    // 备份数据区
            memset(backupData, 0, BACKUP_DATA_SIZE);  // 重置备份数据区

            char* backupDataPtr{backupData};    // 备份数据区指针
            std::size_t readRetryCount{0};  // 读取重试次数

            while (true) {
                // 判断重试次数是否超限(重试3次)，如果超限则停止读取，表示备份完毕
                if (readRetryCount >= 2) {
                    // 向服务端写结束符
                    while (libssh2_channel_send_eof(channel) == LIBSSH2_ERROR_EAGAIN) {
                        s_waitSocket(socketfd, session);
                    }

                    // 释放资源
                    libssh2_channel_close(channel);
                    libssh2_channel_free(channel);
                    libssh2_session_free(session);
                    LIBSSH2_SOCKET_CLOSE(socketfd);
                    break;
                }

                // 通道读取缓存
                constexpr std::size_t CHANNEL_BUFFER_SIZE = 1024 * 10;   // 通道缓存区字节大小
                char channelBuffer[CHANNEL_BUFFER_SIZE];    // 通道缓存区
                memset(channelBuffer, 0, CHANNEL_BUFFER_SIZE);  // 重置通道缓存区

                // 已读到的字节数
                std::int32_t readBytesCount{0};

                do {
                    // fprintf(stdout, "BackupData:\n");
                    // for (std::size_t i = 0; i < 10240; ++i)
                    //     fputc(backupData[i], stdout);
                    // fprintf(stdout, "\n");

                    // 处理完数据后，重置缓存
                    memset(channelBuffer, 0, CHANNEL_BUFFER_SIZE);

                    // 尝试读取数据
                    readBytesCount = libssh2_channel_read(channel, channelBuffer, CHANNEL_BUFFER_SIZE);

                    // 如果读取到了数据，则进行处理
                    if (readBytesCount > 0) {
                        // 读到数据后，重置重试次数
                        readRetryCount = 0;

                        // 如果搜索到了more关键字
                        boost::smatch matches;
                        if (boost::regex_search(std::string{channelBuffer}, matches, s_backupResultMoreSearchRegxPattern)) {
                            // 查看返回的字符串中，是否含有 More 符号
                            char* moreSymbolPtr = strstr(channelBuffer, matches[0].str().c_str());
                            // 如果存在more符号，则先过滤，再进行拷贝
                            if (moreSymbolPtr != NULL) {
                                // backupDataPtr永远指向下一个空的区域
                                memcpy(backupDataPtr, channelBuffer, moreSymbolPtr - channelBuffer);
                                // 移动备份数据指针到下一个空白区
                                backupDataPtr += (moreSymbolPtr - channelBuffer);

                                // 如果包含了more符号，则继续向服务端发送换行符，继续读取
                                std::int32_t moreBytesCount{0};
                                while ((moreBytesCount = libssh2_channel_write(channel, " ", strlen(" "))) == LIBSSH2_ERROR_EAGAIN) {
                                    s_waitSocket(socketfd, session);
                                }
                                if (moreBytesCount < 0){
                                    SPDLOG_INFO("向SSH服务端写入More指令失败..");
                                }

                                // 继续下一次读取
                                continue;
                            }
                        }

                        // 将读到的数据，存储到备份数据中
                        memcpy(backupDataPtr, channelBuffer, readBytesCount);
                        // 移动备份数据指针到下一个空白区
                        backupDataPtr += readBytesCount;
                    }

                    // 休息一会再读
                    // std::this_thread::sleep_for(std::chrono::milliseconds(50));
                }
                while (readBytesCount > 0) ; // 如果这次读取到了数据，则继续下一次读取

                // 如果这次尝试读取失败，看是否是服务端还未响应完，没响应完则等待
                if (readBytesCount == LIBSSH2_ERROR_EAGAIN) {
                    // 等待socket响应
                    s_waitSocket(socketfd, session);
                    // 如果服务器确认响应完了，读取确认就是失败的了，则记录重试次数
                    readRetryCount ++;
                }
            }

            // 设置备份内容
            testResult.backupData = {backupData, static_cast<std::size_t>(backupDataPtr-backupData)};
            // 过滤登录行信息
            boost::algorithm::replace_regex(testResult.backupData, s_backupResultLoginLineFilterRegxPattern, std::string{""}, boost::format_first_only);
            // 终止循环
            break;
        }

        // 回调上报
        m_onTestedCallback(std::move(testResult));

        // 任务结束后，自动回收当前的self资源
    });
}

HandleSSHBackupTestIPv4::~HandleSSHBackupTestIPv4()
{

}

void tag_invoke(boost::json::value_from_tag, boost::json::value &jv, SSHBackupTestResultIPv6 const &c)
{
    auto& ja = jv.emplace_object();

    ja["interface"] = c.interface;
    ja["target"] = c.target;
    ja["port"] = c.port;
    ja["backupData"] = c.backupData;
}

HandleSSHBackupTestIPv6::HandleSSHBackupTestIPv6(SSHBackupTestParamsIPv6&& testParams)
: m_interface(testParams.interface), m_target(testParams.target), m_port(testParams.port), m_username(testParams.username),
m_password(testParams.password), m_privilegedPassword(testParams.privilegedPassword), m_command(testParams.command)
{
    // 初始化libssh2库，在应用程序启动时，只调用一次
    std::call_once(g_libssh2InitOnceFlag, [] {
        // 初始化正常
        if (libssh2_init(0)) {
            SPDLOG_ERROR("libssh2库加载失败...");
            throw std::runtime_error("libssh2库加载失败...");
        }
    });
}

void HandleSSHBackupTestIPv6::setOnTestedCallback(std::function<void(SSHBackupTestResultIPv6 &&)> callback)
{
    m_onTestedCallback = std::move(callback);
}

void HandleSSHBackupTestIPv6::test()
{
    // 指向当前对象的shared_ptr
    auto self{shared_from_this()};

    // 执行备份任务
    m_onTestedCallbackFuture = std::async(std::launch::async, [this, self]() {
        // 备份结果对象
        SSHBackupTestResultIPv6 testResult {
            .interface = m_interface,
            .target = m_target,
            .port = m_port,
            .backupData = ""
        };

        // 尝试3次备份，成功1次则停止
        for (std::size_t i = 0; i < 3; i ++) {
            int rc{0};  // libssh执行结果

            // 创建socket(套接字) [AF_INET: IPv4, SOCK_STREAM: TCP]
            int socketfd = socket(AF_INET6, SOCK_STREAM, 0);
            if (socketfd < 0) {
                // 输出日志
                SPDLOG_INFO("sockfd创建失败: {}", strerror(errno));
                // 结束执行
                continue;
            }

            // 设定本地网卡地址
            struct sockaddr_in6 interfaceAddr;
            memset(&interfaceAddr, 0, sizeof(interfaceAddr));
            interfaceAddr.sin6_family = AF_INET6;
            interfaceAddr.sin6_port = htons(0);
            if (inet_pton(AF_INET6, m_interface.c_str(), &interfaceAddr.sin6_addr) <= 0) {
                // 关闭socket
                close(socketfd);
                // 输出日志
                SPDLOG_INFO("sockfd: {} - 网口地址设置失败: {}", socketfd, strerror(errno));
                // 结束执行
                continue;
            }

            // 绑定本机网口
            if (bind(socketfd, (sockaddr *)&interfaceAddr, sizeof(interfaceAddr)) < 0) {
                // 关闭socket
                close(socketfd);
                // 输出日志
                SPDLOG_INFO("sockfd: {} - 网口地址绑定失败: {}", socketfd, strerror(errno));
                // 结束执行
                continue;
            }

            // 设置目标地址
            struct sockaddr_in6 targetAddr;
            memset(&targetAddr, 0, sizeof(targetAddr));
            targetAddr.sin6_family = AF_INET6;
            targetAddr.sin6_port = htons(m_port);
            if (inet_pton(AF_INET6, m_target.c_str(), &targetAddr.sin6_addr) <= 0) {
                // 关闭socket
                close(socketfd);
                // 输出日志
                SPDLOG_INFO("sockfd: {} - 目标地址设置失败: {}", socketfd, strerror(errno));
                // 结束执行
                continue;
            }

            // 连接目标地址
            if (connect(socketfd, (struct sockaddr *)&targetAddr, sizeof(targetAddr)) < 0) {
                // 关闭socket
                close(socketfd);
                // 输出日志
                SPDLOG_INFO("服务器连接失败: {}", strerror(errno));
                // 结束执行
                continue;
            }

            // 创建SSH会话
            LIBSSH2_SESSION* session = libssh2_session_init();
            if (!session) {
                // 关闭socket
                LIBSSH2_SOCKET_CLOSE(socketfd);
                // 输出日志
                SPDLOG_INFO("sockfd: {} - SSH会话创建失败: {}", socketfd, strerror(errno));
                // 结束执行
                continue;
            }

            // 设置会话为非阻塞模式
            libssh2_session_set_blocking(session, 0);

            // SSH会话握手，握手没有结果时等待
            while ((rc = libssh2_session_handshake(session, socketfd)) == LIBSSH2_ERROR_EAGAIN) {
                s_waitSocket(socketfd, session);
            }

            // 握手有结果时，如果握手失败
            if (rc != 0) {
                // 释放session
                libssh2_session_free(session);
                // 关闭socket
                LIBSSH2_SOCKET_CLOSE(socketfd);
                // 输出日志
                SPDLOG_INFO("sockfd: {} - 握手失败: {}", socketfd, strerror(errno));
                // 结束执行
                continue;
            }

            // 握手成功后，进行帐号认证.未出结果时等待
            while ((rc = libssh2_userauth_password(session, m_username.c_str(), m_password.c_str())) == LIBSSH2_ERROR_EAGAIN) {
                s_waitSocket(socketfd, session);
            }

            // 认证出结果后，如果认证失败
            if (rc != 0) {
                // 释放session
                libssh2_session_free(session);
                // 关闭socket
                LIBSSH2_SOCKET_CLOSE(socketfd);
                // 输出日志
                SPDLOG_INFO("sockfd: {} - 帐号密码认证失败: {}", socketfd, strerror(errno));
                // 结束执行
                continue;
            }

            // 打开通道
            LIBSSH2_CHANNEL* channel = nullptr;
            // 如果通道打开中，则等待
            while ((channel = libssh2_channel_open_session(session)) == NULL && libssh2_session_last_error(session, NULL, NULL, 0) == LIBSSH2_ERROR_EAGAIN) {
                s_waitSocket(socketfd, session);
            }
            // 通道打开出结果后，如果通道打开失败
            if(!channel) {
                // 释放session
                libssh2_session_free(session);
                // 关闭socket
                LIBSSH2_SOCKET_CLOSE(socketfd);
                // 输出日志
                SPDLOG_INFO("sockfd: {} - 通道打开失败: {}", socketfd, strerror(errno));
                // 结束执行
                continue;
            }

            // 请求虚拟终端，未出结果时等待
            while ((rc = libssh2_channel_request_pty(channel, "xterm")) == LIBSSH2_ERROR_EAGAIN) {
                s_waitSocket(socketfd, session);
            }
            // 出结果后，如果请求失败
            if (rc != 0) {
                // 关闭channel
                libssh2_channel_close(channel);
                // 释放channel
                libssh2_channel_free(channel);
                // 释放session
                libssh2_session_free(session);
                // 关闭socket
                LIBSSH2_SOCKET_CLOSE(socketfd);
                // 输出日志
                SPDLOG_INFO("sockfd: {} - 虚拟终端请求失败: {}", socketfd, strerror(errno));
                // 结束执行
                continue;
            }

            // 请求互动shell
            while ((rc = libssh2_channel_shell(channel)) == LIBSSH2_ERROR_EAGAIN) {
                s_waitSocket(socketfd, session);
            }
            if (rc != 0) {
                // 关闭channel
                libssh2_channel_close(channel);
                // 释放channel
                libssh2_channel_free(channel);
                // 释放session
                libssh2_session_free(session);
                // 关闭socket
                LIBSSH2_SOCKET_CLOSE(socketfd);
                // 输出日志
                SPDLOG_INFO("sockfd: {} - 互动shell创建失败: {}", socketfd, strerror(errno));
                // 结束执行
                continue;
            }

            // // 执行命令 命令末尾追加换行，让其可执行
            // std::string command = m_command;

            while ((rc = libssh2_channel_write(channel, m_command.c_str(), strlen(m_command.c_str()))) == LIBSSH2_ERROR_EAGAIN) {
                s_waitSocket(socketfd, session);
            }
            // 如果执行命令失败
            if (rc <= 0) {
                // 关闭channel
                libssh2_channel_close(channel);
                // 释放channel
                libssh2_channel_free(channel);
                // 释放session
                libssh2_session_free(session);
                // 关闭socket
                LIBSSH2_SOCKET_CLOSE(socketfd);
                // 输出日志
                SPDLOG_INFO("sockfd: {} - 备份命令执行失败: {}", socketfd, strerror(errno));
                // 结束执行
                continue;
            }

            // 读取命令执行的结果
            constexpr std::size_t BACKUP_DATA_SIZE = 50 * 1024;  // 备份数据区尺寸
            char backupData[BACKUP_DATA_SIZE];    // 备份数据区
            memset(backupData, 0, BACKUP_DATA_SIZE);  // 重置备份数据区

            char* backupDataPtr{backupData};    // 备份数据区指针
            std::size_t readRetryCount{0};  // 读取重试次数

            while (true) {
                // 判断重试次数是否超限(重试3次)，如果超限则停止读取，表示备份完毕
                if (readRetryCount >= 2) {
                    // 向服务端写结束符
                    while (libssh2_channel_send_eof(channel) == LIBSSH2_ERROR_EAGAIN) {
                        s_waitSocket(socketfd, session);
                    }

                    // 释放资源
                    libssh2_channel_close(channel);
                    libssh2_channel_free(channel);
                    libssh2_session_free(session);
                    LIBSSH2_SOCKET_CLOSE(socketfd);
                    break;
                }

                // 通道读取缓存
                constexpr std::size_t CHANNEL_BUFFER_SIZE = 1024 * 10;   // 通道缓存区字节大小
                char channelBuffer[CHANNEL_BUFFER_SIZE];    // 通道缓存区
                memset(channelBuffer, 0, CHANNEL_BUFFER_SIZE);  // 重置通道缓存区

                // 已读到的字节数
                std::int32_t readBytesCount{0};

                do {
                    // fprintf(stdout, "BackupData:\n");
                    // for (std::size_t i = 0; i < 10240; ++i)
                    //     fputc(backupData[i], stdout);
                    // fprintf(stdout, "\n");

                    // 处理完数据后，重置缓存
                    memset(channelBuffer, 0, CHANNEL_BUFFER_SIZE);

                    // 尝试读取数据
                    readBytesCount = libssh2_channel_read(channel, channelBuffer, CHANNEL_BUFFER_SIZE);

                    // 如果读取到了数据，则进行处理
                    if (readBytesCount > 0) {
                        // 读到数据后，重置重试次数
                        readRetryCount = 0;

                        // 如果搜索到了more关键字
                        boost::smatch matches;
                        if (boost::regex_search(std::string{channelBuffer}, matches, s_backupResultMoreSearchRegxPattern)) {
                            // 查看返回的字符串中，是否含有 More 符号
                            char* moreSymbolPtr = strstr(channelBuffer, matches[0].str().c_str());
                            // 如果存在more符号，则先过滤，再进行拷贝
                            if (moreSymbolPtr != NULL) {
                                // backupDataPtr永远指向下一个空的区域
                                memcpy(backupDataPtr, channelBuffer, moreSymbolPtr - channelBuffer);
                                // 移动备份数据指针到下一个空白区
                                backupDataPtr += (moreSymbolPtr - channelBuffer);

                                // 如果包含了more符号，则继续向服务端发送换行符，继续读取
                                std::int32_t moreBytesCount{0};
                                while ((moreBytesCount = libssh2_channel_write(channel, " ", strlen(" "))) == LIBSSH2_ERROR_EAGAIN) {
                                    s_waitSocket(socketfd, session);
                                }
                                if (moreBytesCount < 0){
                                    SPDLOG_INFO("向SSH服务端写入More指令失败..");
                                }

                                // 继续下一次读取
                                continue;
                            }
                        }

                        // 将读到的数据，存储到备份数据中
                        memcpy(backupDataPtr, channelBuffer, readBytesCount);
                        // 移动备份数据指针到下一个空白区
                        backupDataPtr += readBytesCount;
                    }

                    // 休息一会再读
                    // std::this_thread::sleep_for(std::chrono::milliseconds(50));
                }
                while (readBytesCount > 0) ; // 如果这次读取到了数据，则继续下一次读取

                // 如果这次尝试读取失败，看是否是服务端还未响应完，没响应完则等待
                if (readBytesCount == LIBSSH2_ERROR_EAGAIN) {
                    // 等待socket响应
                    s_waitSocket(socketfd, session);
                    // 如果服务器确认响应完了，读取确认就是失败的了，则记录重试次数
                    readRetryCount ++;
                }
            }

            // 设置备份内容
            testResult.backupData = {backupData, static_cast<std::size_t>(backupDataPtr-backupData)};
            // 过滤登录行信息
            boost::algorithm::replace_regex(testResult.backupData, s_backupResultLoginLineFilterRegxPattern, std::string{""}, boost::format_first_only);
            // 终止循环
            break;
        }

        // 回调上报
        m_onTestedCallback(std::move(testResult));

        // 任务结束后，自动回收当前的self资源
    });
}

HandleSSHBackupTestIPv6::~HandleSSHBackupTestIPv6()
{

}
}